import ByteBuffer = require("bytebuffer")


export default class Packet {
	public packetId: number = 0

	private _buffer: ByteBuffer


	constructor(buffer?: ByteBuffer) {
		this._buffer = buffer ? buffer : new ByteBuffer()
	}


	public Encode(packetId: number) {
		this.packetId = packetId

		const all = new ByteBuffer(4 + this._buffer.offset)

		all.writeUint16(this._buffer.offset + 2)
		all.writeUint16(packetId)
		all.append(this._buffer.slice(0, this._buffer.offset))

		this._buffer = all
	}

	public Buffer(): Buffer {
		return this._buffer.slice(0, this._buffer.offset).buffer
	}

	public GetBuffer(): ByteBuffer {
		return this._buffer
	}

	public WriteBuffer(v: ByteBuffer) {
		this._buffer.append(v.slice(0, v.offset))
	}

	public Reset() {
		this._buffer.reset()
	}


	public WriteByte(v: number) {
		this._buffer.writeUint8(v)
	}

	public WriteSbyte(v: number) {
		this._buffer.writeInt8(v)
	}

	public WriteUshort(v: number) {
		this._buffer.writeUint16(v)
	}

	public WriteShort(v: number) {
		this._buffer.writeInt16(v)
	}

	public WriteUint(v: number) {
		this._buffer.writeUint32(v)
	}

	public WriteInt(v: number) {
		this._buffer.writeInt32(v)
	}

	public WriteUlong(v) {
		this._buffer.writeUint64(v)
	}

	public WriteLong(v) {
		this._buffer.writeInt64(v)
	}

	public WriteFloat(v: number) {
		this._buffer.writeFloat32(v)
	}

	public WriteDouble(v: number) {
		this._buffer.writeFloat64(v)
	}

	public WriteString(v: string) {
		const len = ByteBuffer.calculateUTF8Bytes(v)

		this.WriteUshort(len)
		this._buffer.writeString(v)
	}

	public WriteBin(v: Uint8Array) {
		this.WriteUint(v.length)
		this._buffer.append(v)
	}


	public ReadByte(): number {
		return this._buffer.readUint8()
	}

	public ReadSbyte(): number {
		return this._buffer.readInt8()
	}

	public ReadUshort(): number {
		return this._buffer.readUint16()
	}

	public ReadShort(): number {
		return this._buffer.readInt16()
	}

	public ReadUint(): number {
		return this._buffer.readUint32()
	}

	public ReadInt(): number {
		return this._buffer.readInt32()
	}

	public ReadUlong() {
		return this._buffer.readUint64()
	}

	public ReadLong() {
		return this._buffer.readInt64()
	}

	public ReadFloat(): number {
		return this._buffer.readFloat32()
	}

	public ReadDouble(): number {
		return this._buffer.readFloat64()
	}

	public ReadString(): string {
		const len = this.ReadUshort()
		
		return this._buffer.readString(len, ByteBuffer.METRICS_BYTES)
	}

	public ReadBin(): Uint8Array {
		const len = this.ReadUint()

		const bytes = this._buffer.readBytes(len)

		return new Uint8Array(bytes.toArrayBuffer())
	}
}
